import uuid
import json
import os
import logging
from typing import Dict, List, Optional, Any, Tuple
from datetime import datetime

from ..models.base import (
    Question, GradingCriteria, StudentAnswer, GradingResult,
    KeywordMatch, GradingRequest, BatchGradingRequest
)
from ..services.ai_service import ai_service, AIRequest

logger = logging.getLogger(__name__)


class GradingDataManager:
    """评分数据管理器，负责数据的存储和检索."""

    def __init__(self, data_dir: str = "data/grading"):
        self.data_dir = data_dir
        self.questions_file = os.path.join(data_dir, "questions.json")
        self.criteria_file = os.path.join(data_dir, "criteria.json")
        self.answers_file = os.path.join(data_dir, "answers.json")
        self.results_file = os.path.join(data_dir, "results.json")

        self._ensure_data_dir()
        self._init_data_files()

    def _ensure_data_dir(self):
        """确保数据目录存在."""
        os.makedirs(self.data_dir, exist_ok=True)

    def _init_data_files(self):
        """初始化数据文件."""
        files = [self.questions_file, self.criteria_file, self.answers_file, self.results_file]
        for file_path in files:
            if not os.path.exists(file_path):
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump({}, f, ensure_ascii=False, indent=2)

    def _load_data(self, file_path: str) -> Dict[str, Any]:
        """加载JSON数据."""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            logger.error(f"加载数据失败: {file_path}, 错误: {e}")
            return {}

    def _save_data(self, file_path: str, data: Dict[str, Any]):
        """保存JSON数据."""
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2, default=str)
        except Exception as e:
            logger.error(f"保存数据失败: {file_path}, 错误: {e}")
            raise

    # 题目管理
    def save_question(self, question: Question) -> bool:
        """保存题目."""
        try:
            data = self._load_data(self.questions_file)
            data[question.id] = question.model_dump()
            self._save_data(self.questions_file, data)
            return True
        except Exception as e:
            logger.error(f"保存题目失败: {e}")
            return False

    def get_question(self, question_id: str) -> Optional[Question]:
        """获取题目."""
        data = self._load_data(self.questions_file)
        if question_id in data:
            return Question(**data[question_id])
        return None

    def list_questions(self) -> List[Question]:
        """获取所有题目."""
        data = self._load_data(self.questions_file)
        return [Question(**q) for q in data.values()]

    def delete_question(self, question_id: str) -> bool:
        """删除题目."""
        try:
            data = self._load_data(self.questions_file)
            if question_id in data:
                del data[question_id]
                self._save_data(self.questions_file, data)
                return True
            return False
        except Exception as e:
            logger.error(f"删除题目失败: {e}")
            return False

    # 评分标准管理
    def save_criteria(self, criteria: GradingCriteria) -> bool:
        """保存评分标准."""
        try:
            data = self._load_data(self.criteria_file)
            data[criteria.id] = criteria.model_dump()
            self._save_data(self.criteria_file, data)
            return True
        except Exception as e:
            logger.error(f"保存评分标准失败: {e}")
            return False

    def get_criteria(self, criteria_id: str) -> Optional[GradingCriteria]:
        """获取评分标准."""
        data = self._load_data(self.criteria_file)
        if criteria_id in data:
            return GradingCriteria(**data[criteria_id])
        return None

    def get_criteria_by_question(self, question_id: str) -> List[GradingCriteria]:
        """获取题目相关的评分标准."""
        data = self._load_data(self.criteria_file)
        criteria_list = []
        for criteria_data in data.values():
            if criteria_data.get('question_id') == question_id:
                criteria_list.append(GradingCriteria(**criteria_data))
        return criteria_list

    def delete_criteria(self, criteria_id: str) -> bool:
        """删除评分标准."""
        try:
            data = self._load_data(self.criteria_file)
            if criteria_id in data:
                del data[criteria_id]
                self._save_data(self.criteria_file, data)
                return True
            return False
        except Exception as e:
            logger.error(f"删除评分标准失败: {e}")
            return False

    # 学生答案管理
    def save_answer(self, answer: StudentAnswer) -> bool:
        """保存学生答案."""
        try:
            data = self._load_data(self.answers_file)
            data[answer.id] = answer.model_dump()
            self._save_data(self.answers_file, data)
            return True
        except Exception as e:
            logger.error(f"保存学生答案失败: {e}")
            return False

    def get_answer(self, answer_id: str) -> Optional[StudentAnswer]:
        """获取学生答案."""
        data = self._load_data(self.answers_file)
        if answer_id in data:
            return StudentAnswer(**data[answer_id])
        return None

    # 评分结果管理
    def save_grading_result(self, result: GradingResult) -> bool:
        """保存评分结果."""
        try:
            data = self._load_data(self.results_file)
            data[result.id] = result.model_dump()
            self._save_data(self.results_file, data)
            return True
        except Exception as e:
            logger.error(f"保存评分结果失败: {e}")
            return False

    def get_grading_result(self, result_id: str) -> Optional[GradingResult]:
        """获取评分结果."""
        data = self._load_data(self.results_file)
        if result_id in data:
            return GradingResult(**data[result_id])
        return None

    def get_results_by_question(self, question_id: str) -> List[GradingResult]:
        """获取题目的所有评分结果."""
        data = self._load_data(self.results_file)
        results = []
        for result_data in data.values():
            if result_data.get('question_id') == question_id:
                results.append(GradingResult(**result_data))
        return results


class AIGradingEngine:
    """AI评分引擎."""

    def __init__(self):
        self.default_temperature = 0.1  # 保持评分的一致性

    async def grade_answer(self,
                          question: Question,
                          student_answer: str,
                          grading_criteria: Optional[str] = None) -> Tuple[float, List[KeywordMatch], str, List[str], List[str], List[str]]:
        """使用AI评分答案."""

        # 构建评分提示
        prompt = self._build_grading_prompt(question, student_answer, grading_criteria)

        try:
            # 调用AI服务
            messages = [{"role": "user", "content": prompt}]
            response = await ai_service.generate(
                messages=messages,
                temperature=self.default_temperature,
                max_tokens=2000
            )

            # 解析AI响应
            return self._parse_grading_response(response.content, question.points)

        except Exception as e:
            logger.error(f"AI评分失败: {e}")
            # 返回默认结果
            return (
                question.points * 0.5,  # 默认50%分数
                [],  # 空的关键词匹配
                "AI评分服务暂时不可用，请稍后重试。",
                [],  # 空的优点
                ["AI服务暂时不可用"],  # 缺点
                ["请稍后重新评分"]  # 建议
            )

    def _build_grading_prompt(self, question: Question, student_answer: str, grading_criteria: Optional[str]) -> str:
        """构建评分提示."""

        prompt = f"""
请作为一名专业的教师，对以下学生答案进行详细评分和分析。

【题目信息】
标题: {question.title}
内容: {question.content}
类型: {question.question_type}
学科: {question.subject}
满分: {question.points}分
难度: {question.difficulty}

【学生答案】
{student_answer}

【评分标准】
"""

        if grading_criteria and grading_criteria.strip():
            prompt += f"{grading_criteria}\n"
        else:
            prompt += f"""
请根据{question.subject}学科的专业知识和教学标准进行评分。

基于你的知识库，从以下维度综合评估：
1. 内容准确性和完整性 - 答案是否正确且全面
2. 逻辑清晰性和条理性 - 表达是否清晰有条理
3. 关键概念的掌握程度 - 是否掌握核心知识点
4. 答案的深度和广度 - 分析是否深入，覆盖是否全面
5. 表达的规范性和专业性 - 用词是否准确专业

请结合题目的{question.difficulty}难度等级和{question.points}分的分值进行合理评分。
"""

        prompt += """

请按照以下JSON格式返回评分结果：
{
    "score": 评分(数字),
    "score_percentage": 得分百分比,
    "keyword_matches": [
        {
            "keyword": "关键词",
            "position": 在答案中的位置,
            "context": "关键词上下文",
            "score_impact": 对分数的影响(0-100),
            "category": "关键词类别"
        }
    ],
    "strengths": ["答案优点1", "答案优点2"],
    "weaknesses": ["答案不足1", "答案不足2"],
    "suggestions": ["改进建议1", "改进建议2"],
    "detailed_scores": {
        "内容准确性": 分数,
        "逻辑清晰性": 分数,
        "概念掌握": 分数,
        "表达规范": 分数
    },
    "feedback": "详细的评分反馈和分析"
}

请确保：
1. 评分客观公正，有理有据
2. 关键词匹配要准确，包含重要概念
3. 优点和不足要具体明确
4. 建议要具有可操作性
5. 反馈要详细具体，有助于学生改进
"""

        return prompt

    def _parse_grading_response(self, response: str, max_score: int) -> Tuple[float, List[KeywordMatch], str, List[str], List[str], List[str]]:
        """解析AI评分响应."""
        try:
            # 尝试解析JSON响应
            import re

            # 提取JSON部分
            json_match = re.search(r'\{.*\}', response, re.DOTALL)
            if json_match:
                json_str = json_match.group()
                result = json.loads(json_str)
            else:
                # 如果没有找到JSON，尝试解析文本
                return self._parse_text_response(response, max_score)

            # 解析评分信息
            score = float(result.get('score', max_score * 0.5))
            score = min(max(score, 0), max_score)  # 确保分数在有效范围内

            # 解析关键词匹配
            keyword_matches = []
            for km in result.get('keyword_matches', []):
                keyword_matches.append(KeywordMatch(
                    keyword=km.get('keyword', ''),
                    position=int(km.get('position', 0)),
                    context=km.get('context', ''),
                    score_impact=float(km.get('score_impact', 0)),
                    category=km.get('category', 'general')
                ))

            feedback = result.get('feedback', '评分完成')
            strengths = result.get('strengths', [])
            weaknesses = result.get('weaknesses', [])
            suggestions = result.get('suggestions', [])

            return score, keyword_matches, feedback, strengths, weaknesses, suggestions

        except Exception as e:
            logger.error(f"解析AI响应失败: {e}")
            return self._parse_text_response(response, max_score)

    def _parse_text_response(self, response: str, max_score: int) -> Tuple[float, List[KeywordMatch], str, List[str], List[str], List[str]]:
        """解析文本响应（备用方法）."""
        # 简单的文本解析逻辑
        score = max_score * 0.7  # 默认70%
        feedback = response if response else "评分完成"

        return (
            score,
            [],  # 空的关键词匹配
            feedback,
            ["答案有一定的理解"],  # 默认优点
            ["需要更详细的分析"],  # 默认缺点
            ["加强相关知识点的学习"]  # 默认建议
        )


class GradingService:
    """评分服务主类."""

    def __init__(self, data_dir: str = "data/grading"):
        self.data_manager = GradingDataManager(data_dir)
        self.ai_engine = AIGradingEngine()

    # 题目管理
    def create_question(self, title: str, content: str, question_type: str,
                       subject: str, difficulty: str = "medium", points: int = 100,
                       tags: List[str] = None) -> Question:
        """创建新题目."""
        question = Question(
            id=str(uuid.uuid4()),
            title=title,
            content=content,
            question_type=question_type,
            subject=subject,
            difficulty=difficulty,
            points=points,
            tags=tags or []
        )

        if self.data_manager.save_question(question):
            logger.info(f"创建题目成功: {question.id}")
            return question
        else:
            raise Exception("保存题目失败")

    def get_question(self, question_id: str) -> Optional[Question]:
        """获取题目."""
        return self.data_manager.get_question(question_id)

    def list_questions(self) -> List[Question]:
        """获取所有题目."""
        return self.data_manager.list_questions()

    # 评分标准管理
    def create_grading_criteria(self, question_id: str, criteria_text: str,
                              key_points: List[str] = None,
                              deduction_rules: List[str] = None,
                              weight_distribution: Dict[str, float] = None) -> GradingCriteria:
        """创建评分标准."""
        criteria = GradingCriteria(
            id=str(uuid.uuid4()),
            question_id=question_id,
            criteria_text=criteria_text,
            key_points=key_points or [],
            deduction_rules=deduction_rules or [],
            weight_distribution=weight_distribution or {}
        )

        if self.data_manager.save_criteria(criteria):
            logger.info(f"创建评分标准成功: {criteria.id}")
            return criteria
        else:
            raise Exception("保存评分标准失败")

    def get_criteria_by_question(self, question_id: str) -> List[GradingCriteria]:
        """获取题目的评分标准."""
        return self.data_manager.get_criteria_by_question(question_id)

    # 核心评分功能
    async def grade_single_answer(self, request: GradingRequest) -> GradingResult:
        """评分单个答案."""
        # 获取题目信息
        question = self.data_manager.get_question(request.question_id)
        if not question:
            raise ValueError(f"题目不存在: {request.question_id}")

        # 获取评分标准
        criteria_text = request.grading_criteria
        if request.use_existing_criteria and not criteria_text:
            existing_criteria = self.data_manager.get_criteria_by_question(request.question_id)
            if existing_criteria:
                criteria_text = existing_criteria[0].criteria_text

        # 保存学生答案
        answer = StudentAnswer(
            id=str(uuid.uuid4()),
            question_id=request.question_id,
            student_id=request.student_id or "anonymous",
            student_name=request.student_name or "匿名学生",
            answer_content=request.student_answer
        )
        self.data_manager.save_answer(answer)

        # AI评分
        score, keyword_matches, feedback, strengths, weaknesses, suggestions = \
            await self.ai_engine.grade_answer(question, request.student_answer, criteria_text)

        # 创建评分结果
        result = GradingResult(
            id=str(uuid.uuid4()),
            answer_id=answer.id,
            question_id=request.question_id,
            score=score,
            max_score=float(question.points),
            score_percentage=round((score / question.points) * 100, 2),
            keyword_matches=keyword_matches,
            strengths=strengths,
            weaknesses=weaknesses,
            suggestions=suggestions,
            detailed_scores={},
            feedback=feedback,
            confidence=0.8  # 默认置信度
        )

        # 保存评分结果
        self.data_manager.save_grading_result(result)

        logger.info(f"评分完成: {result.id}, 得分: {score}/{question.points}")
        return result

    async def grade_batch_answers(self, request: BatchGradingRequest) -> List[GradingResult]:
        """批量评分答案."""
        results = []

        for answer_data in request.answers:
            try:
                # 创建单个评分请求
                single_request = GradingRequest(
                    question_id=request.question_id,
                    student_answer=answer_data.get('answer', ''),
                    student_id=answer_data.get('student_id'),
                    student_name=answer_data.get('student_name'),
                    grading_criteria=request.grading_criteria,
                    use_existing_criteria=request.use_existing_criteria,
                    detailed_feedback=request.detailed_feedback
                )

                # 评分
                result = await self.grade_single_answer(single_request)
                results.append(result)

            except Exception as e:
                logger.error(f"批量评分中单个答案评分失败: {e}")
                continue

        logger.info(f"批量评分完成: {len(results)}/{len(request.answers)}")
        return results

    def get_grading_statistics(self, question_id: str) -> Dict[str, Any]:
        """获取评分统计信息."""
        results = self.data_manager.get_results_by_question(question_id)

        if not results:
            return {"total_count": 0}

        scores = [r.score for r in results]
        percentages = [r.score_percentage for r in results]

        return {
            "total_count": len(results),
            "average_score": round(sum(scores) / len(scores), 2),
            "average_percentage": round(sum(percentages) / len(percentages), 2),
            "max_score": max(scores),
            "min_score": min(scores),
            "score_distribution": self._get_score_distribution(percentages)
        }

    def _get_score_distribution(self, percentages: List[float]) -> Dict[str, int]:
        """获取分数分布."""
        distribution = {
            "优秀(90-100)": 0,
            "良好(80-89)": 0,
            "中等(70-79)": 0,
            "及格(60-69)": 0,
            "不及格(0-59)": 0
        }

        for percentage in percentages:
            if percentage >= 90:
                distribution["优秀(90-100)"] += 1
            elif percentage >= 80:
                distribution["良好(80-89)"] += 1
            elif percentage >= 70:
                distribution["中等(70-79)"] += 1
            elif percentage >= 60:
                distribution["及格(60-69)"] += 1
            else:
                distribution["不及格(0-59)"] += 1

        return distribution


# 创建全局评分服务实例
grading_service = GradingService()